home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr44 / frasrc19.zip / CALMANFP.ASM < prev    next >
Assembly Source File  |  1994-09-24  |  66KB  |  1,815 lines

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ; calmanfp.asm - floating point version of the calcmand.asm file
  3. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4. ; The following code was adapted from a little program called "Mandelbrot
  5. ; Sets by Wesley Loewer" which had a very limited distribution (my
  6. ; Algebra II class).  It didn't have any of the fancy integer math, but it
  7. ; did run floating point stuff pretty fast.
  8. ;
  9. ; The code was originally optimized for a 287 ('cuz that's what I've got)
  10. ; and for a large maxit (ie: use of generous overhead outside the loop to get
  11. ; slightly faster code inside the loop), which is generally the case when
  12. ; Fractint chooses to use floating point math.  This code also has the
  13. ; advantage that once the initial parameters are loaded into the fpu
  14. ; register, no transfers of fp values to/from memory are needed except to
  15. ; check periodicity and to show orbits and the like.  Thus, values keep all
  16. ; the significant digits of the full 10 byte real number format internal to
  17. ; the fpu.  Intermediate results are not rounded to the normal IEEE 8 byte
  18. ; format (double) at any time.
  19. ;
  20. ; The non fpu specific stuff, such as periodicity checking and orbits,
  21. ; was adapted from CALCFRAC.C and CALCMAND.ASM.
  22. ;
  23. ; This file must be assembled with floating point emulation turned on.  I
  24. ; suppose there could be some compiler differences in the emulation
  25. ; libraries, but this code has been successfully tested with the MSQC 2.51
  26. ; and MSC 5.1 emulation libraries.
  27. ;
  28. ;                                               Wes Loewer
  29. ;
  30. ; and now for some REAL fractal calculations...
  31. ; (get it, real, floating point..., never mind)
  32. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  33.  
  34. ;   1. Made maxit a dword variable. 1/18/94
  35.  
  36. ;                        required for compatibility if Turbo ASM
  37. IFDEF ??version
  38. MASM51
  39. QUIRKS
  40. ENDIF
  41.  
  42. .8086
  43. .8087
  44.  
  45. .MODEL medium,c
  46.  
  47. ; external functions
  48. EXTRN   keypressed:FAR          ; this routine is in 'general.asm'
  49. EXTRN   getakey:FAR             ; this routine is in 'general.asm'
  50. EXTRN   plot_orbit:FAR          ; this routine is in 'fracsubr.c'
  51. EXTRN   scrub_orbit:FAR         ; this routine is in 'fracsubr.c'
  52.  
  53. ; external data
  54. EXTRN init:WORD                 ; declared as type complex
  55. EXTRN parm:WORD                 ; declared as type complex
  56. EXTRN new:WORD                  ; declared as type complex
  57. EXTRN maxit:DWORD
  58. EXTRN inside:WORD
  59. EXTRN outside:WORD
  60. EXTRN fpu:WORD                  ; fpu type: 87, 287, or 387
  61. EXTRN cpu:WORD                  ; cpu type
  62. EXTRN rqlim:QWORD               ; bailout (I never did figure out
  63.                 ;   what "rqlim" stands for. -Wes)
  64. EXTRN coloriter:DWORD
  65. EXTRN oldcoloriter:DWORD
  66. EXTRN realcoloriter:DWORD
  67. EXTRN periodicitycheck:WORD
  68. EXTRN reset_periodicity:WORD
  69. EXTRN closenuff:QWORD
  70. EXTRN fractype:WORD             ; Mandelbrot or Julia
  71. EXTRN kbdcount:WORD            ; keyboard counter
  72. EXTRN dotmode:WORD
  73. EXTRN show_orbit:WORD           ; "show-orbit" flag
  74. EXTRN orbit_ptr:WORD            ; "orbit pointer" flag
  75. EXTRN potflag:WORD              ; potential flag
  76. EXTRN magnitude:QWORD           ; when using potential
  77. extrn    nextsavedincr:word        ; for incrementing AND value
  78. extrn    firstsavedand:dword        ; AND value
  79.  
  80. JULIAFP  EQU 6                  ; from FRACTYPE.H
  81. MANDELFP EQU 4
  82. GREEN    EQU 2                  ; near y-axis
  83. YELLOW   EQU 6                  ; near x-axis
  84. KEYPRESSDELAY equ 16383         ; 3FFFh
  85.  
  86. initx    EQU <qword ptr init>   ; just to make life easier
  87. inity    EQU <qword ptr init+8>
  88. parmx    EQU <qword ptr parm>
  89. parmy    EQU <qword ptr parm+8>
  90. newx     EQU <qword ptr new>
  91. newy     EQU <qword ptr new+8>
  92.  
  93. ; Apparently, these might be needed for TC++ overlays. I don't know if
  94. ; these are really needed here since I am not familiar with TC++. -Wes
  95. FRAME   MACRO regs
  96.     push    bp
  97.     mov     bp, sp
  98.     IRP     reg, <regs>
  99.       push  reg
  100.       ENDM
  101.     ENDM
  102.  
  103. UNFRAME MACRO regs
  104.     IRP     reg, <regs>
  105.       pop reg
  106.       ENDM
  107.     pop bp
  108.     ENDM
  109.  
  110.  
  111. .DATA
  112.     align   2
  113. savedx                  DQ  ?
  114. savedy                  DQ  ?
  115. orbit_real              DQ  ?
  116. orbit_imag              DQ  ?
  117. _2_                     DQ  2.0
  118. _4_                     DQ  4.0
  119. close                   DD  0.01
  120. round_down_half         DD  0.5
  121. one_8_zero              DD  180.0
  122. tmp_word                DW  ?
  123. tmp_dword               DD  ?
  124. inside_color            DD  ?
  125. periodicity_color       DW  ?
  126. savedand                DD  ?   ; need 4 bytes now, not 2
  127. ;savedincr              DW  ?
  128. ;savedand                EQU     SI      ; this doesn't save much time or
  129. savedincr               EQU     DI      ; space, but it doesn't hurt either
  130.  
  131. .CODE
  132.  
  133. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  134. ; This routine is called once per image.
  135. ; Put things here that won't change from one pixel to the next.
  136. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  137. PUBLIC calcmandfpasmstart
  138. calcmandfpasmstart   PROC
  139.                     ; not sure if needed here
  140.     FRAME   <di,si>                 ; std frame, for TC++ overlays
  141.  
  142.     mov     ax,inside
  143.     cmp     ax,0                    ; if (inside color == maxiter)
  144.     jnl     non_neg_inside
  145.     mov     ax,word ptr maxit       ;   use maxit as inside_color
  146.     mov     dx,word ptr maxit+2     ;   use maxit as inside_color
  147.  
  148. non_neg_inside:                         ; else
  149.     mov     word ptr inside_color,ax  ;   use inside as inside_color
  150.     mov     word ptr inside_color+2,dx ;   use inside as inside_color
  151.  
  152.     cmp     periodicitycheck,0      ; if periodicitycheck < 0
  153.     jnl     non_neg_periodicitycheck
  154.     mov     ax,7                    ;   use color 7 (default white)
  155. non_neg_periodicitycheck:               ; else
  156.     mov     periodicity_color,ax    ;   use inside_color still in ax
  157.     mov     word ptr oldcoloriter,0 ; no periodicity checking on 1st pixel
  158.     mov     word ptr oldcoloriter+2,0 ; no periodicity checking on 1st pixel
  159.     sub     ax,ax                   ; ax=0
  160.     sub     dx,dx
  161.     UNFRAME <si,di>                 ; pop stack frame
  162.     ret
  163. calcmandfpasmstart       ENDP
  164.  
  165. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  166. ; floating point version of calcmandasm
  167. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  168. PUBLIC calcmandfpasm
  169. calcmandfpasm  PROC
  170.     FRAME   <di,si>                 ; std frame, for TC++ overlays
  171. ; initialization stuff
  172.     sub     ax,ax                   ; clear ax
  173.     mov     dx,ax                   ; dx=0
  174.     cmp     periodicitycheck,ax     ; periodicity checking?
  175.     je      initoldcolor            ;  no, set oldcolor 0 to disable it
  176.     cmp     inside,-59              ; zmag?
  177.     je      initoldcolor            ;  set oldcolor to 0
  178.     cmp     reset_periodicity,ax    ; periodicity reset?
  179.     je      short initparms         ;  no, inherit oldcolor from prior invocation
  180.     mov    ax,word ptr maxit        ; yup.    reset oldcolor to maxit-250
  181.     mov    dx,word ptr maxit+2
  182.     sub    ax,250            ; (avoids slowness at high maxits)
  183.     sbb    dx,0                ; (faster than conditional jump)
  184. initoldcolor:
  185.     mov     word ptr oldcoloriter,ax   ; reset oldcolor
  186.     mov     word ptr oldcoloriter+2,dx ; reset oldcolor
  187.  
  188. initparms:
  189.     sub     ax,ax                   ; clear ax
  190.     mov     dx,ax                   ; clear dx
  191.     mov     word ptr savedx,ax      ; savedx = 0.0
  192.     mov     word ptr savedx+2,ax    ; needed since savedx is a QWORD
  193.     mov     word ptr savedx+4,ax
  194.     mov     word ptr savedx+6,ax
  195.     mov     word ptr savedy,ax      ; savedy = 0.0
  196.     mov     word ptr savedy+2,ax    ; needed since savedy is a QWORD
  197.     mov     word ptr savedy+4,ax
  198.     mov     word ptr savedy+6,ax
  199.     mov     ax,word ptr firstsavedand+2 ; high part of savedand=0
  200.     mov     word ptr savedand+2,ax ; high part of savedand=0
  201.     mov     ax,word ptr firstsavedand    ; low part of savedand
  202.     mov     word ptr savedand,ax    ; low part of savedand
  203.     mov     savedincr,1             ; savedincr = 1
  204.     mov     orbit_ptr,0             ; clear orbits
  205.     dec     kbdcount                ; decrement the keyboard counter
  206.     jns     short step_nokey        ;  skip keyboard test if still positive
  207.     mov     kbdcount,10             ; stuff in a low kbd count
  208.     cmp     show_orbit,0            ; are we showing orbits?
  209.     jne     quickkbd                ;  yup.  leave it that way.
  210. ;this may need to be adjusted, I'm guessing at the "appropriate" values -Wes
  211.     mov     kbdcount,5000           ; else, stuff an appropriate count val
  212.     cmp     fpu,387                 ; ("appropriate" to the FPU)
  213.     je      short kbddiskadj        ;     ...
  214.     mov     kbdcount,3000           ;     ...
  215.     cmp     fpu,287                 ;     ...
  216.     je      short kbddiskadj        ;     ...
  217.     mov     kbdcount,1000           ;     ...
  218.     cmp     fpu,87                  ;     ...
  219.     je      short kbddiskadj        ;     ...
  220.     mov     kbdcount,500            ; emulation
  221.     jmp    short kbddiskadj
  222. step_nokey:
  223.     jmp    nokey
  224. kbddiskadj:
  225.     cmp     dotmode,11              ; disk video?
  226.     jne     quickkbd                ;  no, leave as is
  227.     shr     kbdcount,1              ; yes, reduce count
  228.     shr     kbdcount,1              ; yes, reduce count
  229.  
  230. quickkbd:
  231.     call    far ptr keypressed      ; has a key been pressed?
  232.     cmp     ax,0                    ;  ...
  233.     je      nokey                   ; nope.  proceed
  234.     mov     kbdcount,0              ; make sure it goes negative again
  235.     cmp     ax,'o'                  ; orbit toggle hit?
  236.     je      orbitkey                ;  yup.  show orbits
  237.     cmp     ax,'O'                  ; orbit toggle hit?
  238.     jne     keyhit                  ;  nope.  normal key.
  239. orbitkey:
  240.     call    far ptr getakey         ; read the key for real
  241.     mov     ax,1                    ; reset orbittoggle = 1 - orbittoggle
  242.     sub     ax,show_orbit           ;  ...
  243.     mov     show_orbit,ax           ;  ...
  244.     jmp     short nokey             ; pretend no key was hit
  245. keyhit:
  246.     mov     ax,-1                   ; return with -1
  247.     mov     dx,ax
  248.     mov     word ptr coloriter,ax   ; set color to -1
  249.     mov     word ptr coloriter+2,ax ; set color to -1
  250.     UNFRAME <si,di>                 ; pop stack frame
  251.     ret                             ; bail out!
  252. nokey:
  253.  
  254. ; OK, here's the heart of the floating point code.
  255. ; In my original program, the bailout value was loaded once per image and
  256. ; was left on the floating point stack after each pixel, and finally popped
  257. ; off the stack when the fractal was finished.  A lot of overhead for very
  258. ; little gain in my opinion, so I changed it so that it loads and unloads
  259. ; per pixel. -Wes
  260.  
  261.     fld     rqlim                   ; everything needs bailout first
  262.     cmp    cpu,386
  263.     je    check_for_386_387
  264. not_a_386_387:
  265.     mov     cx,word ptr maxit+2     ; using cx and bx as loop counter
  266.     mov     bx,word ptr maxit       ; using cx and bx as loop counter
  267.     cmp     fpu,387                 ; jump to fpu specific code
  268.     je      start_387               ; 387, slight efficiency tweeking
  269.     cmp     fpu,287                 ;
  270.     je      to_start_287            ; 287 (original version)
  271.     jmp     start_87                ; else must be 87/emulation
  272. to_start_287:
  273.     jmp     start_287               ; needs a long jump here
  274. check_for_386_387:
  275.     cmp    fpu,387
  276.     jb    not_a_386_387
  277. .386
  278.     mov    ecx,maxit
  279. .8086
  280.     jmp    start_386_387
  281.  
  282. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  283. ; _387 code is just like _287 code except that it uses an FADD instead
  284. ; of an FSCALE per orbit and also saves an FLD1 per pixel.
  285. ;
  286. ; You could use .386/.387 here, but it is not necessary.  The _387 floating
  287. ; point routines in this file do not have any 387 specific op-codes,
  288. ; only 387 specific optimizations.  (And plus my MS QuickAssembler does not
  289. ; recognize the .386/.387 directives.) -Wes
  290. ;
  291. .286
  292. .287
  293. start_387:
  294.     cmp     fractype,JULIAFP        ; julia or mandelbrot set?
  295.     je      short dojulia_387       ; julia set - go there
  296.  
  297. ; Mandelbrot _387 initialization of stack
  298.     sub     bx,1                      ; always requires at least 1 iteration
  299.     sbb     cx,0
  300.                     ; the fpu stack is shown below
  301.                     ; st(0) ... st(7)
  302.                     ; b (already on stack)
  303.     fld     inity                   ; Cy b
  304.     fld     initx                   ; Cx Cy b
  305.     fld     st(1)                   ; Cy Cx Cy b
  306.     fadd    parmy                   ; Py+Cy Cx Cy b
  307.     fld     st                      ; Py+Cy Py+Cy Cx Cy b
  308.     fmul    st,st                   ; (Py+Cy)^2 Py+Cy Cx Cy b
  309.     fld     st(2)                   ; Cx (Py+Cy)^2 Py+Cy Cx Cy b
  310.     fadd    parmx                   ; Px+Cx (Py+Cy)^2 Py+Cy Cx Cy b
  311.     fmul    st(2),st                ; Px+Cx (Py+Cy)^2 (Py+Cy)(Px+Cx) Cx Cy b
  312.     fmul    st,st                   ; (Px+Cx)^2 (Py+Cy)^2 (Py+Cy)(Px+Cx) Cx Cy b
  313.     ; which is the next               x^2 y^2 xy Cx Cy b
  314.     jmp     short top_of_cx_loop_387 ; branch around the julia switch
  315.  
  316. dojulia_387:
  317.                     ; Julia 387 initialization of stack
  318.                     ; note that init and parm are "reversed"
  319.                     ; b (already on stack)
  320.     fld     parmy                   ; Cy b
  321.     fld     parmx                   ; Cx Cy b
  322.     fld     inity                   ; y Cx Cy b
  323.     fld     st                      ; y y Cx Cy b
  324.     fmul    st,st                   ; y^2 y Cx Cy b
  325.     fld     initx                   ; x y^2 y Cx Cy b
  326.     fmul    st(2),st                ; x y^2 xy Cx Cy b
  327.     fmul    st,st                   ; x^2 y^2 xy Cx Cy b
  328.  
  329. top_of_cx_loop_387:                     ; x^2 y^2 xy Cx Cy b
  330.     fsubr                           ; x^2-y^2 xy Cx Cy b
  331.     fadd    st,st(2)                ; x^2-y^2+Cx xy Cx Cy b
  332.     fxch                            ; xy x^2-y^2+Cx Cx Cy b
  333. ; FADD is faster than FSCALE for 387
  334.     fadd    st,st                   ; 2xy x^2-y^2+Cx Cx Cy b
  335.     fadd    st,st(3)                ; 2xy+Cy x^2-y^2+Cx Cx Cy b
  336.                     ; now same as the new
  337.                     ; y x Cx Cy b
  338.  
  339.     cmp     outside,-2              ; real, imag, mult, or sum ?
  340.     jg      no_save_new_xy_387      ; if not, then skip this
  341.     fld     st(1)                   ; x y x Cx Cy b
  342.     fstp    newx                    ; y x Cx Cy b
  343.     fst     newy                    ; y x Cx Cy b
  344. no_save_new_xy_387:
  345.  
  346.     cmp     inside,-100                     ; epsilon cross ?
  347.     jne     end_epsilon_cross_387
  348.     call    near ptr epsilon_cross          ; y x Cx Cy b
  349.     cmp    bx,0
  350.     jnz    end_epsilon_cross_387
  351.     cmp    cx,0
  352.     jnz   end_epsilon_cross_387                   ; if cx=0, pop stack
  353.     jmp    pop_stack_387
  354. end_epsilon_cross_387:
  355.  
  356.     test    bx,KEYPRESSDELAY    ; bx holds the low word of the loop count
  357.     jne    notakey1        ; don't test yet
  358.     push    cx
  359.     push    bx
  360.     call    far ptr keypressed    ; has a key been pressed?
  361.     pop    bx
  362.     pop    cx
  363.     cmp    ax,0            ;  ...
  364.     je    notakey1            ; nope.  proceed
  365.     jmp    keyhit
  366. notakey1:
  367.  
  368.     cmp     cx,word ptr oldcoloriter+2      ; if cx > oldcoloriter
  369.     ja      end_periodicity_check_387       ; don't check periodicity
  370.     cmp     bx,word ptr oldcoloriter        ; if bx >= oldcoloriter
  371.     jae     end_periodicity_check_387       ; don't check periodicity
  372.     call    near ptr periodicity_check_287_387  ; y x Cx Cy b
  373.     cmp    bx,0
  374.     jnz    end_periodicity_check_387
  375.     cmp    cx,0
  376.     jnz    end_periodicity_check_387       ; if cx=0, pop stack
  377.     jmp    pop_stack_387
  378. end_periodicity_check_387:
  379.  
  380.     cmp     show_orbit,0            ; is show_orbit clear
  381.     je      no_show_orbit_387       ; if so then skip
  382.     call    near ptr show_orbit_xy  ; y x Cx Cy b
  383. no_show_orbit_387:
  384.  
  385.                     ; y x Cx Cy b
  386.     fld     st(1)                   ; x y x Cx Cy b
  387.     fld     st(1)                   ; y x y x Cx Cy b
  388.     fmul    st(3),st                ; y x y xy Cx Cy b
  389.     fmulp   st(2),st                ; x y^2 xy Cx Cy b
  390.     fmul    st,st                   ; x^2 y^2 xy Cx Cy b
  391.     fld     st                      ; x^2 x^2 y^2 xy Cx Cy b
  392.     fadd    st,st(2)                ; x^2+y^2 x^2 y^2 xy Cx Cy b
  393.  
  394.     cmp     potflag,0               ; check for potential
  395.     je      no_potflag_387
  396.     fst     magnitude               ; if so, save magnitude
  397. no_potflag_387:
  398.  
  399.     fcomp   st(6)                   ; x^2 y^2 xy Cx Cy b
  400.     fstsw   ax
  401.     sahf
  402.     ja      over_bailout_387
  403.  
  404. ;less than or equal to bailout
  405. ;    loop   top_of_cx_loop_387      ; x^2 y^2 xy Cx Cy b
  406.     sub    bx,1
  407.     sbb    cx,0
  408.     jnz    top_of_cx_loop_387
  409.     cmp    bx,0
  410.     jnz    top_of_cx_loop_387
  411.  
  412. ; reached maxit, inside
  413.     mov     word ptr oldcoloriter,-1   ; check periodicity immediately next time
  414.     mov     word ptr oldcoloriter+2,-1 ; check periodicity immediately next time
  415.     mov     ax,word ptr maxit
  416.     mov     dx,word ptr maxit+2
  417.     sub     kbdcount,ax                 ; adjust the keyboard count
  418.     mov     word ptr realcoloriter,ax   ; save unadjusted realcoloriter
  419.     mov     word ptr realcoloriter+2,dx ; save unadjusted realcoloriter
  420.     mov     ax,word ptr inside_color
  421.     mov     dx,word ptr inside_color+2
  422.  
  423.     cmp     inside,-59              ; zmag ?
  424.     jne     no_zmag_387
  425.     fadd    st,st(1)                ; x^2+y^2 y^2 xy Cx Cy b
  426.     fimul   maxit                   ; maxit*|z^2| x^2 y^2 xy Cx Cy b
  427.  
  428. ; When type casting floating point variables to integers in C, the decimal
  429. ; is truncated.  When using FIST in asm, the value is rounded.  The following
  430. ; line cause the positive value to be truncated.
  431.     fsub    round_down_half
  432.  
  433.     fist    tmp_dword                ; tmp_word = |z^2|*maxit
  434.     fwait
  435.     mov     ax,word ptr tmp_dword
  436.     mov     dx,word ptr tmp_dword+2
  437.     shr     dx,1                    ; |z^2|*maxit/2
  438.     rcr     ax,1
  439.     add     ax,1                    ; |z^2|*maxit/2+1
  440.     adc     dx,0
  441.  
  442. no_zmag_387:
  443.  
  444. pop_stack_387:
  445.     fninit
  446.  
  447.     mov     word ptr coloriter,ax
  448.     mov     word ptr coloriter+2,dx
  449.  
  450.     cmp     orbit_ptr,0             ; any orbits to clear?
  451.     je      calcmandfpasm_ret_387   ; nope.
  452.     call    far ptr scrub_orbit     ; clear out any old orbits
  453.     mov     ax,word ptr coloriter   ; restore color
  454.     mov     dx,word ptr coloriter+2 ; restore color
  455.                     ; speed not critical here in orbit land
  456.  
  457. calcmandfpasm_ret_387:
  458.     UNFRAME <si,di>                 ; pop stack frame
  459.     fwait                ; just to make sure
  460.     ret
  461.  
  462.     
  463. over_bailout_387:                       ; x^2 y^2 xy Cx Cy b
  464. ; outside
  465.     mov     dx,cx
  466.     mov     ax,bx
  467.     sub     ax,10                   ; 10 more next time before checking
  468.     sbb     dx,0
  469.     jns     no_fix_underflow_387
  470. ; if the number of iterations was within 10 of maxit, then subtracting
  471. ; 10 would underflow and cause periodicity checking to start right
  472. ; away.  Catching a period doesn't occur as often in the pixels at
  473. ; the edge of the set anyway.
  474.     sub     ax,ax                   ; don't check next time
  475.     mov     dx,ax
  476. no_fix_underflow_387:
  477.     mov     word ptr oldcoloriter,ax ; check when past this - 10 next time
  478.     mov     word ptr oldcoloriter+2,dx ; check when past this - 10 next time
  479.     mov     ax,word ptr maxit
  480.     mov     dx,word ptr maxit+2
  481.     sub     ax,bx                   ; leave 'times through loop' in ax
  482.     sbb     dx,cx                   ; and dx
  483.  
  484. ; zero color fix
  485.     jnz     zero_color_fix_387
  486.     cmp     ax,0
  487.     jnz     zero_color_fix_387
  488.     inc     ax                      ; if (ax == 0 ) ax = 1
  489. zero_color_fix_387:
  490.     mov     word ptr realcoloriter,ax   ; save unadjusted realcolor
  491.     mov     word ptr realcoloriter+2,dx ; save unadjusted realcolor
  492.     sub     kbdcount,ax                 ; adjust the keyboard count
  493.  
  494.     cmp     outside,-1              ; iter ? (most common case)
  495.     je      pop_stack_387
  496.     cmp     outside,-2        ; outside <= -2 ?
  497.     jle     special_outside_387     ; yes, go do special outside options
  498.     mov     ax,outside              ; use outside color
  499.     sub     dx,dx
  500.     jmp     short pop_stack_387
  501. special_outside_387:
  502.     call    near ptr special_outside
  503.     jmp     short pop_stack_387
  504.  
  505. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  506. ; _386_387 code is just like _287 code except that it uses an FADD
  507. ; instead of an FSCALE per orbit and also saves an FLD1 per pixel.
  508. ; And uses 386 specific speedups.
  509. ;
  510. .386
  511. .387
  512. start_386_387:
  513.     cmp     fractype,JULIAFP        ; julia or mandelbrot set?
  514.     je      short dojulia_386_387   ; julia set - go there
  515.  
  516. ; Mandelbrot _386_387 initialization of stack
  517.     dec     ecx                     ; always requires at least 1 iteration
  518.                     ; the fpu stack is shown below
  519.                     ; st(0) ... st(7)
  520.                     ; b (already on stack)
  521.     fld     inity                   ; Cy b
  522.     fld     initx                   ; Cx Cy b
  523.     fld     st(1)                   ; Cy Cx Cy b
  524.     fadd    parmy                   ; Py+Cy Cx Cy b
  525.     fld     st                      ; Py+Cy Py+Cy Cx Cy b
  526.     fmul    st,st                   ; (Py+Cy)^2 Py+Cy Cx Cy b
  527.     fld     st(2)                   ; Cx (Py+Cy)^2 Py+Cy Cx Cy b
  528.     fadd    parmx                   ; Px+Cx (Py+Cy)^2 Py+Cy Cx Cy b
  529.     fmul    st(2),st                ; Px+Cx (Py+Cy)^2 (Py+Cy)(Px+Cx) Cx Cy b
  530.     fmul    st,st                   ; (Px+Cx)^2 (Py+Cy)^2 (Py+Cy)(Px+Cx) Cx Cy b
  531.     ; which is the next               x^2 y^2 xy Cx Cy b
  532.     jmp     short top_of_cx_loop_386_387 ; branch around the julia switch
  533.  
  534. dojulia_386_387:
  535.                     ; Julia 387 initialization of stack
  536.                     ; note that init and parm are "reversed"
  537.                     ; b (already on stack)
  538.     fld     parmy                   ; Cy b
  539.     fld     parmx                   ; Cx Cy b
  540.     fld     inity                   ; y Cx Cy b
  541.     fld     st                      ; y y Cx Cy b
  542.     fmul    st,st                   ; y^2 y Cx Cy b
  543.     fld     initx                   ; x y^2 y Cx Cy b
  544.     fmul    st(2),st                ; x y^2 xy Cx Cy b
  545.     fmul    st,st                   ; x^2 y^2 xy Cx Cy b
  546.  
  547. top_of_cx_loop_386_387:               ; x^2 y^2 xy Cx Cy b
  548.     fsubr                           ; x^2-y^2 xy Cx Cy b
  549.     fadd    st,st(2)                ; x^2-y^2+Cx xy Cx Cy b
  550.     fxch                            ; xy x^2-y^2+Cx Cx Cy b
  551. ; FADD is faster than FSCALE for 387
  552.     fadd    st,st                   ; 2xy x^2-y^2+Cx Cx Cy b
  553.     fadd    st,st(3)                ; 2xy+Cy x^2-y^2+Cx Cx Cy b
  554.                     ; now same as the new
  555.                     ; y x Cx Cy b
  556.  
  557.     cmp     outside,-2              ; real, imag, mult, or sum ?
  558.     jg      no_save_new_xy_386_387  ; if not, then skip this
  559.     fld     st(1)                   ; x y x Cx Cy b
  560.     fstp    newx                    ; y x Cx Cy b
  561.     fst     newy                    ; y x Cx Cy b
  562. no_save_new_xy_386_387:
  563.  
  564.     cmp     inside,-100                     ; epsilon cross ?
  565.     jne     end_epsilon_cross_386_387
  566.     call    near ptr epsilon_cross_386_387  ; y x Cx Cy b
  567.     jecxz   step_to_pop_stack_386_387       ; if ecx=0, pop stack
  568. end_epsilon_cross_386_387:
  569.  
  570.     test    ecx,KEYPRESSDELAY    ; ecx holds the loop count
  571.     jne    notakey2        ; don't test yet
  572.     push    ecx
  573.     call    far ptr keypressed    ; has a key been pressed?
  574.     pop    ecx
  575.     cmp    ax,0            ;  ...
  576.     je    notakey2            ; nope.  proceed
  577.     jmp    keyhit
  578. notakey2:
  579.  
  580.     cmp     ecx,oldcoloriter                ; if ecx > oldcolor
  581.     jae     end_periodicity_check_386_387   ; don't check periodicity
  582.     call    near ptr periodicity_check_386_387  ; y x Cx Cy b
  583.     jecxz   step_to_pop_stack_386_387       ; if ecx=0, pop stack
  584.     jmp     short end_periodicity_check_386_387
  585. step_to_pop_stack_386_387:
  586.     jmp     short pop_stack_386_387
  587. end_periodicity_check_386_387:
  588.  
  589.     cmp     show_orbit,0            ; is show_orbit clear
  590.     je      no_show_orbit_386_387       ; if so then skip
  591.     call    near ptr show_orbit_xy  ; y x Cx Cy b
  592. no_show_orbit_386_387:
  593.  
  594.                     ; y x Cx Cy b
  595.     fld     st(1)                   ; x y x Cx Cy b
  596.     fld     st(1)                   ; y x y x Cx Cy b
  597.     fmul    st(3),st                ; y x y xy Cx Cy b
  598.     fmulp   st(2),st                ; x y^2 xy Cx Cy b
  599.     fmul    st,st                   ; x^2 y^2 xy Cx Cy b
  600.     fld     st                      ; x^2 x^2 y^2 xy Cx Cy b
  601.     fadd    st,st(2)                ; x^2+y^2 x^2 y^2 xy Cx Cy b
  602.  
  603.     cmp     potflag,0               ; check for potential
  604.     je      no_potflag_386_387
  605.     fst     magnitude               ; if so, save magnitude
  606. no_potflag_386_387:
  607.  
  608.     fcomp   st(6)                   ; x^2 y^2 xy Cx Cy b
  609.     fstsw   ax
  610.     sahf
  611.     ja      over_bailout_386_387
  612.  
  613. ;less than or equal to bailout
  614. ;    loopd   top_of_cx_loop_386_387      ; x^2 y^2 xy Cx Cy b
  615.     dec     ecx
  616.     jnz     top_of_cx_loop_386_387
  617.  
  618. ; reached maxit, inside
  619.     mov     oldcoloriter,-1        ; check periodicity immediately next time
  620.     mov     eax,maxit
  621.     sub     kbdcount,ax            ; adjust the keyboard count
  622.     mov     realcoloriter,eax      ; save unadjusted realcolor
  623.     mov     eax,inside_color
  624.  
  625.     cmp     inside,-59              ; zmag ?
  626.     jne     no_zmag_386_387
  627.     fadd    st,st(1)                ; x^2+y^2 y^2 xy Cx Cy b
  628.     fimul   maxit                   ; maxit*|z^2| x^2 y^2 xy Cx Cy b
  629.  
  630. ; When type casting floating point variables to integers in C, the decimal
  631. ; is truncated.  When using FIST in asm, the value is rounded.  The following
  632. ; line cause the positive value to be truncated.
  633.     fsub    round_down_half
  634.  
  635.     fist    tmp_dword               ; tmp_dword = |z^2|*maxit
  636.     fwait
  637.     mov     eax,tmp_dword
  638.     shr     eax,1                    ; |z^2|*maxit/2
  639.     inc     eax                      ; |z^2|*maxit/2+1
  640.  
  641. no_zmag_386_387:
  642.  
  643. pop_stack_386_387:
  644.     fninit
  645.  
  646.     mov     coloriter,eax
  647.  
  648.     cmp     orbit_ptr,0             ; any orbits to clear?
  649.     je      calcmandfpasm_ret_386_387 ; nope.
  650.     call    far ptr scrub_orbit     ; clear out any old orbits
  651.     mov     eax,coloriter           ; restore color
  652.                     ; speed not critical here in orbit land
  653.  
  654. calcmandfpasm_ret_386_387:
  655.     shld    edx,eax,16        ; put results in ax,dx
  656.     shr    eax,16
  657.     UNFRAME <si,di>                 ; pop stack frame
  658.     fwait                ; just to make sure
  659.     ret
  660.  
  661.     
  662. over_bailout_386_387:                       ; x^2 y^2 xy Cx Cy b
  663. ; outside
  664.     mov     eax,ecx
  665.     sub     eax,10                   ; 10 more next time before checking
  666.     jns     no_fix_underflow_386_387
  667. ; if the number of iterations was within 10 of maxit, then subtracting
  668. ; 10 would underflow and cause periodicity checking to start right
  669. ; away.  Catching a period doesn't occur as often in the pixels at
  670. ; the edge of the set anyway.
  671.     sub     eax,eax                  ; don't check next time
  672. no_fix_underflow_386_387:
  673.     mov     oldcoloriter,eax         ; check when past this - 10 next time
  674.     mov     eax,maxit
  675.     sub     eax,ecx                  ; leave 'times through loop' in eax
  676.  
  677. ; zero color fix
  678.     jnz     zero_color_fix_386_387
  679.     inc     eax                      ; if (eax == 0 ) eax = 1
  680. zero_color_fix_386_387:
  681.     mov     realcoloriter,eax        ; save unadjusted realcolor
  682.     sub     kbdcount,ax              ; adjust the keyboard count
  683.  
  684.     cmp     outside,-1              ; iter ? (most common case)
  685.     je      pop_stack_386_387
  686.     cmp     outside,-2        ; outside <= -2 ?
  687.     jle     to_special_outside_386_387 ; yes, go do special outside options
  688.     sub     eax,eax                ; clear top half of eax for next
  689.     mov     ax,outside             ; use outside color
  690.     jmp     short pop_stack_386_387
  691. to_special_outside_386_387:
  692.     call    near ptr special_outside_386_387
  693.     jmp     short pop_stack_386_387
  694.  
  695. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  696. ; _287 version (closely resembles original code)
  697. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  698. .286
  699. .287
  700. start_287:      ; 287
  701.     cmp     fractype,JULIAFP        ; julia or mandelbrot set?
  702.     je      short dojulia_287       ; julia set - go there
  703.  
  704. ; Mandelbrot _287 initialization of stack
  705.     sub     bx,1                      ; always requires at least 1 iteration
  706.     sbb     cx,0
  707.                     ; the fpu stack is shown below
  708.                     ; st(0) ... st(7)
  709.                     ; b (already on stack)
  710.     fld     inity                   ; Cy b
  711.     fld     initx                   ; Cx Cy b
  712.     fld     st(1)                   ; Cy Cx Cy b
  713.     fadd    parmy                   ; Py+Cy Cx Cy b
  714.     fld1                            ; 1 Py+Cy Cx Cy b
  715.     fld     st(1)                   ; Py+Cy 1 Py+Cy Cx Cy b
  716.     fmul    st,st                   ; (Py+Cy)^2 1 Py+Cy Cx Cy b
  717.     fld     st(3)                   ; Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  718.     fadd    parmx                   ; Px+Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  719.     fmul    st(3),st                ; Px+Cx (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  720.     fmul    st,st                   ; (Px+Cx)^2 (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  721.     ; which is the next                x^2 y^2 1 xy Cx Cy b
  722.     jmp     short top_of_cx_loop_287 ; branch around the julia switch
  723.  
  724. dojulia_287:
  725.                     ; Julia 287 initialization of stack
  726.                     ; note that init and parm are "reversed"
  727.                     ; b (already on stack)
  728.     fld     parmy                   ; Cy b
  729.     fld     parmx                   ; Cx Cy b
  730.     fld     inity                   ; y Cx Cy b
  731.     fld1                            ; 1 y Cx Cy b
  732.     fld     st(1)                   ; y 1 y Cx Cy b
  733.     fmul    st,st                   ; y^2 1 y Cx Cy b
  734.     fld     initx                   ; x y^2 1 y Cx Cy b
  735.     fmul    st(3),st                ; x y^2 1 xy Cx Cy b
  736.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  737.  
  738. top_of_cx_loop_287:                     ; x^2 y^2 1 xy Cx Cy b
  739.     fsubr                           ; x^2-y^2 1 xy Cx Cy b
  740.     fadd    st,st(3)                ; x^2-y^2+Cx 1 xy Cx Cy b
  741.     fxch    st(2)                   ; xy 1 x^2-y^2+Cx Cx Cy b
  742. ; FSCALE is faster than FADD for 287
  743.     fscale                          ; 2xy 1 x^2-y^2+Cx Cx Cy b
  744.     fadd    st,st(4)                ; 2xy+Cy 1 x^2-y^2+Cx Cx Cy b
  745.                     ; now same as the new
  746.                     ; y 1 x Cx Cy b
  747.  
  748.     cmp     outside,-2              ; real, imag, mult, or sum ?
  749.     jg      no_save_new_xy_287      ; if not, then skip this
  750.     fld     st(2)                   ; x y 1 x Cx Cy b
  751.     fstp    newx                    ; y 1 x Cx Cy b
  752.     fst     newy                    ; y 1 x Cx Cy b
  753. no_save_new_xy_287:
  754.  
  755.     cmp     inside,-100                     ; epsilon cross ?
  756.     jne     end_epsilon_cross_287
  757.     call    near ptr epsilon_cross          ; y 1 x Cx Cy b
  758.     cmp    bx,0
  759.     jnz    end_epsilon_cross_287
  760.     cmp    cx,0
  761.     jnz   end_epsilon_cross_287             ; if cx=0, pop stack
  762.     jmp    pop_stack_287
  763. end_epsilon_cross_287:
  764.  
  765.     test    bx,KEYPRESSDELAY    ; bx holds the low word of the loop count
  766.     jne    notakey3        ; don't test yet
  767.     push    cx
  768.     push    bx
  769.     call    far ptr keypressed    ; has a key been pressed?
  770.     pop    bx
  771.     pop    cx
  772.     cmp    ax,0            ;  ...
  773.     je    notakey3            ; nope.  proceed
  774.     jmp    keyhit
  775. notakey3:
  776.  
  777.     cmp     cx,word ptr oldcoloriter+2      ; if cx > oldcolor
  778.     ja      end_periodicity_check_287       ; don't check periodicity
  779.     cmp     bx,word ptr oldcoloriter        ; if bx >= oldcolor
  780.     jae     end_periodicity_check_287       ; don't check periodicity
  781.     call    near ptr periodicity_check_287_387 ; y 1 x Cx Cy b
  782.     cmp    bx,0
  783.     jnz    end_periodicity_check_287
  784.     cmp    cx,0
  785.     jnz   end_periodicity_check_287                   ; if cx=0, pop stack
  786.     jmp    pop_stack_287
  787. end_periodicity_check_287:
  788.  
  789.     cmp     show_orbit,0            ; is show_orbit clear
  790.     je      no_show_orbit_287       ; if so then skip
  791.     call    near ptr show_orbit_xy  ; y 1 x Cx Cy b
  792. no_show_orbit_287:
  793.                     ; y 1 x Cx Cy b
  794.     fld     st(2)                   ; x y 1 x Cx Cy b
  795.     fld     st(1)                   ; y x y 1 x Cx Cy b
  796.     fmul    st(4),st                ; y x y 1 xy Cx Cy b
  797.     fmulp   st(2),st                ; x y^2 1 xy Cx Cy b
  798.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  799.     fld     st                      ; x^2 x^2 y^2 1 xy Cx Cy b
  800.     fadd    st,st(2)                ; x^2+y^2 x^2 y^2 1 xy Cx Cy b
  801.  
  802.     cmp     potflag,0        ; check for potential
  803.     je      no_potflag_287
  804.     fst     magnitude        ; if so, save magnitude
  805. no_potflag_287:
  806.  
  807.     fcomp   st(7)                   ; x^2 y^2 1 xy Cx Cy b
  808.     fstsw   ax
  809.     sahf
  810.     ja      over_bailout_287
  811.  
  812. ;less than or equal to bailout
  813. ;    loop    top_of_cx_loop_287      ; x^2 y^2 1 xy Cx Cy b
  814.     sub    bx,1
  815.     sbb    cx,0
  816.     jnz    top_of_cx_loop_287
  817.     cmp    bx,0
  818.     jnz    top_of_cx_loop_287
  819.  
  820. ; reached maxit, inside
  821.     mov     word ptr oldcoloriter,-1   ; check periodicity immediately next time
  822.     mov     word ptr oldcoloriter+2,-1 ; check periodicity immediately next time
  823.     mov     ax,word ptr maxit
  824.     mov     dx,word ptr maxit+2
  825.     sub     kbdcount,ax                 ; adjust the keyboard count
  826.     mov     word ptr realcoloriter,ax   ; save unadjusted realcolor
  827.     mov     word ptr realcoloriter+2,dx ; save unadjusted realcolor
  828.     mov     ax,word ptr inside_color
  829.     mov     dx,word ptr inside_color+2
  830.  
  831.     cmp     inside,-59              ; zmag ?
  832.     jne     no_zmag_287
  833.     fadd    st,st(1)                ; x^2+y^2 y^2 1 xy Cx Cy b
  834.     fimul   maxit                   ; maxit*|z^2| x^2 y^2 1 xy Cx Cy b
  835.  
  836. ; When type casting floating point variables to integers in C, the decimal
  837. ; is truncated.  When using FIST in asm, the value is rounded.  The following
  838. ; line cause the positive value to be truncated.
  839.     fsub    round_down_half
  840.  
  841.     fist    tmp_dword                ; tmp_word = |z^2|*maxit
  842.     fwait
  843.     mov     ax,word ptr tmp_dword
  844.     shr     dx,1                    ; |z^2|*maxit/2
  845.     rcr     ax,1
  846.     add     ax,1                    ; |z^2|*maxit/2+1
  847.     adc     dx,0
  848.  
  849. no_zmag_287:
  850.  
  851. pop_stack_287:
  852.     fninit
  853.  
  854.     mov     word ptr coloriter,ax
  855.     mov     word ptr coloriter+2,dx
  856.  
  857.     cmp     orbit_ptr,0             ; any orbits to clear?
  858.     je      calcmandfpasm_ret_287   ; nope.
  859.     call    far ptr scrub_orbit     ; clear out any old orbits
  860.     mov     ax,word ptr coloriter   ; restore color
  861.     mov     dx,word ptr coloriter+2 ; restore color
  862.                     ; speed not critical here in orbit land
  863.  
  864. calcmandfpasm_ret_287:
  865.     UNFRAME <si,di>                 ; pop stack frame
  866.     fwait                           ; just to make sure
  867.     ret
  868.  
  869. over_bailout_287:                       ; x^2 y^2 1 xy Cx Cy b
  870. ; outside
  871.     mov     dx,cx
  872.     mov     ax,bx
  873.     sub     ax,10                   ; 10 more next time before checking
  874.     sbb     dx,0
  875.     jns     no_fix_underflow_287
  876. ; if the number of iterations was within 10 of maxit, then subtracting
  877. ; 10 would underflow and cause periodicity checking to start right
  878. ; away.  Catching a period doesn't occur as often in the pixels at
  879. ; the edge of the set anyway.
  880.     sub     ax,ax                   ; don't check next time
  881.     mov     dx,ax
  882. no_fix_underflow_287:
  883.     mov     word ptr oldcoloriter,ax ; check when past this - 10 next time
  884.     mov     word ptr oldcoloriter+2,dx ; check when past this - 10 next time
  885.     mov     ax,word ptr maxit
  886.     mov     dx,word ptr maxit+2
  887.     sub     ax,bx                   ; leave 'times through loop' in ax
  888.     sbb     dx,cx                   ; and dx
  889.  
  890. ; zero color fix
  891.     jnz     zero_color_fix_287
  892.     cmp     ax,0
  893.     jnz     zero_color_fix_287
  894.     inc     ax                      ; if (ax == 0 ) ax = 1
  895. zero_color_fix_287:
  896.     mov     word ptr realcoloriter,ax   ; save unadjusted realcolor
  897.     mov     word ptr realcoloriter+2,dx ; save unadjusted realcolor
  898.     sub     kbdcount,ax                 ; adjust the keyboard count
  899.  
  900.     cmp     outside,-1              ; iter ? (most common case)
  901.     je      pop_stack_287
  902.     cmp     outside,-2        ; outside <= -2 ?
  903.     jle     special_outside_287     ; yes, go do special outside options
  904.     mov     ax,outside              ; use outside color
  905.     sub     dx,dx
  906.     jmp     short pop_stack_287
  907. special_outside_287:
  908.     call    near ptr special_outside
  909.     jmp     short pop_stack_287
  910.  
  911.  
  912. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  913. ; _87 code is just like 287 code except that it must use
  914. ;       fstsw   tmp_word
  915. ;       fwait
  916. ;       mov     ax,tmp_word
  917. ; instead of
  918. ;       fstsw   ax
  919. ;
  920. .8086
  921. .8087
  922. start_87:
  923. ; let emulation fall through to the 87 code here
  924. ; as it seems not emulate correctly on an 8088/86 otherwise
  925.     cmp     fractype,JULIAFP        ; julia or mandelbrot set?
  926.     je      short dojulia_87        ; julia set - go there
  927.  
  928. ; Mandelbrot _87 initialization of stack
  929.     sub     bx,1                      ; always requires at least 1 iteration
  930.     sbb     cx,0
  931.                     ; the fpu stack is shown below
  932.                     ; st(0) ... st(7)
  933.                     ; b (already on stack)
  934.     fld     inity                   ; Cy b
  935.     fld     initx                   ; Cx Cy b
  936.     fld     st(1)                   ; Cy Cx Cy b
  937.     fadd    parmy                   ; Py+Cy Cx Cy b
  938.     fld1                            ; 1 Py+Cy Cx Cy b
  939.     fld     st(1)                   ; Py+Cy 1 Py+Cy Cx Cy b
  940.     fmul    st,st                   ; (Py+Cy)^2 1 Py+Cy Cx Cy b
  941.     fld     st(3)                   ; Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  942.     fadd    parmx                   ; Px+Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  943.     fmul    st(3),st                ; Px+Cx (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  944.     fmul    st,st                   ; (Px+Cx)^2 (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  945.     ; which is the next               x^2 y^2 1 xy Cx Cy b
  946.     jmp     short top_of_cx_loop_87 ; branch around the julia switch
  947.  
  948. dojulia_87:
  949.                     ; Julia 87 initialization of stack
  950.                     ; note that init and parm are "reversed"
  951.                     ; b (already on stack)
  952.     fld     parmy                   ; Cy b
  953.     fld     parmx                   ; Cx Cy b
  954.     fld     inity                   ; y Cx Cy b
  955.     fld1                            ; 1 y Cx Cy b
  956.     fld     st(1)                   ; y 1 y Cx Cy b
  957.     fmul    st,st                   ; y^2 1 y Cx Cy b
  958.     fld     initx                   ; x y^2 1 y Cx Cy b
  959.     fmul    st(3),st                ; x y^2 1 xy Cx Cy b
  960.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  961.  
  962. top_of_cx_loop_87:                      ; x^2 y^2 1 xy Cx Cy b
  963.     fsubr                           ; x^2-y^2 1 xy Cx Cy b
  964.     fadd    st,st(3)                ; x^2-y^2+Cx 1 xy Cx Cy b
  965.     fxch    st(2)                   ; xy 1 x^2-y^2+Cx Cx Cy b
  966. ; FSCALE is faster than FADD for 87
  967.     fscale                          ; 2xy 1 x^2-y^2+Cx Cx Cy b
  968.     fadd    st,st(4)                ; 2xy+Cy 1 x^2-y^2+Cx Cx Cy b
  969.                     ; now same as the new
  970.                     ; y 1 x Cx Cy b
  971.  
  972.     cmp     outside,-2              ; real, imag, mult, or sum ?
  973.     jg      no_save_new_xy_87       ; if not, then skip this
  974.     fld     st(2)                   ; x y 1 x Cx Cy b
  975.     fstp    newx                    ; y 1 x Cx Cy b
  976.     fst     newy                    ; y 1 x Cx Cy b
  977. no_save_new_xy_87:
  978.  
  979.     cmp     inside,-100                     ; epsilon cross ?
  980.     jne     end_epsilon_cross_87
  981.     call    near ptr epsilon_cross          ; y 1 x Cx Cy b
  982.     cmp    bx,0
  983.     jnz    end_epsilon_cross_87
  984.     cmp    cx,0
  985.     jnz    end_epsilon_cross_87                   ; if cx=0, pop stack
  986.     jmp     pop_stack_6_87                  ; with a long jump
  987. end_epsilon_cross_87:
  988.  
  989.     test    bx,KEYPRESSDELAY    ; bx holds the low word of the loop count
  990.     jne    notakey4        ; don't test yet
  991.     push    cx
  992.     push    bx
  993.     call    far ptr keypressed    ; has a key been pressed?
  994.     pop    bx
  995.     pop    cx
  996.     cmp    ax,0            ;  ...
  997.     je    notakey4            ; nope.  proceed
  998.     jmp    keyhit
  999. notakey4:
  1000.  
  1001.     cmp     cx,word ptr oldcoloriter+2      ; if cx > oldcolor
  1002.     ja      no_periodicity_check_87         ; don't check periodicity
  1003.     cmp     bx,word ptr oldcoloriter        ; if bx >= oldcolor
  1004.     jae     no_periodicity_check_87         ; don't check periodicity
  1005.     call    near ptr periodicity_check_87   ; y 1 x Cx Cy b
  1006.     cmp    bx,0
  1007.     jnz    no_periodicity_check_87
  1008.     cmp    cx,0
  1009.     jnz   no_periodicity_check_87           ; if cx=0, pop stack
  1010.     jmp     pop_stack_6_87
  1011. no_periodicity_check_87:
  1012.  
  1013.     cmp     show_orbit,0            ; is show_orbit clear
  1014.     je      no_show_orbit_87        ; if so then skip
  1015.     call    near ptr show_orbit_xy  ; y 1 x Cx Cy b
  1016. no_show_orbit_87:
  1017.  
  1018.                     ; y 1 x Cx Cy b
  1019.     fld     st(2)                   ; x y 1 x Cx Cy b
  1020.     fld     st(1)                   ; y x y 1 x Cx Cy b
  1021.     fmul    st(4),st                ; y x y 1 xy Cx Cy b
  1022.     fmulp   st(2),st                ; x y^2 1 xy Cx Cy b
  1023.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  1024.     fld     st                      ; x^2 x^2 y^2 1 xy Cx Cy b
  1025.     fadd    st,st(2)                ; x^2+y^2 x^2 y^2 1 xy Cx Cy b
  1026.  
  1027.     cmp     potflag,0               ; check for potential
  1028.     je      no_potflag_87
  1029.     fst     magnitude               ; if so, save magnitude
  1030. no_potflag_87:
  1031.  
  1032.     fcomp   st(7)                   ; x^2 y^2 1 xy Cx Cy b
  1033.     fstsw   tmp_word
  1034.     fwait
  1035.     mov     ax,tmp_word
  1036.     sahf
  1037.     ja      over_bailout_87
  1038.  
  1039. ;less than or equal to bailout
  1040. ;    loop    top_of_cx_loop_87       ; x^2 y^2 1 xy Cx Cy b
  1041.     sub    bx,1
  1042.     sbb    cx,0
  1043.     jnz    top_of_cx_loop_87
  1044.     cmp    bx,0
  1045.     jnz    top_of_cx_loop_87
  1046.  
  1047. ; reached maxit
  1048.     mov     word ptr oldcoloriter,-1   ; check periodicity immediately next time
  1049.     mov     word ptr oldcoloriter+2,-1 ; check periodicity immediately next time
  1050.     mov     ax,word ptr maxit
  1051.     mov     dx,word ptr maxit+2
  1052.     sub     kbdcount,ax                 ; adjust the keyboard count
  1053.     mov     word ptr realcoloriter,ax   ; save unadjusted realcolor
  1054.     mov     word ptr realcoloriter+2,dx ; save unadjusted realcolor
  1055.     mov     ax,word ptr inside_color
  1056.     mov     dx,word ptr inside_color+2
  1057.  
  1058.     cmp     inside,-59              ; zmag ?
  1059.     jne     no_zmag_87
  1060.     fadd    st,st(1)                ; x^2+y^2 y^2 1 xy Cx Cy b
  1061.     fimul   maxit                   ; maxit*|z^2| x^2 y^2 1 xy Cx Cy b
  1062.  
  1063. ; When type casting floating point variables to integers in C, the decimal
  1064. ; is truncated.  When using FIST in asm, the value is rounded.  The following
  1065. ; line cause the positive value to be truncated.
  1066.     fsub    round_down_half
  1067.  
  1068.     fist    tmp_dword                ; tmp_word = |z^2|*maxit
  1069.     fwait
  1070.     mov     ax,word ptr tmp_dword
  1071.     mov     dx,word ptr tmp_dword+2
  1072.     shr     dx,1                    ; |z^2|*maxit/2
  1073.     rcr     ax,1
  1074.     add     ax,1                    ; |z^2|*maxit/2+1
  1075.     adc     dx,0
  1076.  
  1077. no_zmag_87:
  1078.  
  1079. pop_stack_7_87:
  1080. ; The idea here is just to clear the floating point stack.  There was a
  1081. ; problem using FNINIT with the emulation library.  It didn't seem to
  1082. ; properly clear the emulated stack, resulting in "stack overflow"
  1083. ; messages.  Therefore, if emulation is being used, then FSTP's are used
  1084. ; instead.
  1085.  
  1086.     cmp     fpu,0                   ; are we using emulation?
  1087.     jne     no_emulation            ; if not, then jump
  1088.     fstp    st
  1089. ; you could just jump over this next check, but its faster to just check again
  1090. pop_stack_6_87:
  1091.     cmp     fpu,0                   ; are we using emulation?
  1092.     jne     no_emulation            ; if not, then jump
  1093.     fstp    st
  1094.     fstp    st
  1095.     fstp    st
  1096.     fstp    st
  1097.     fstp    st
  1098.     fstp    st
  1099.     jmp     short end_pop_stack_87
  1100. no_emulation:                           ; if no emulation, then
  1101.     fninit                          ;   use the faster FNINIT
  1102. end_pop_stack_87:
  1103.  
  1104.     mov     word ptr coloriter,ax
  1105.     mov     word ptr coloriter+2,dx
  1106.  
  1107.     cmp     orbit_ptr,0             ; any orbits to clear?
  1108.     je      calcmandfpasm_ret_87    ; nope.
  1109.     call    far ptr scrub_orbit     ; clear out any old orbits
  1110.     mov     ax,word ptr coloriter   ; restore color
  1111.     mov     dx,word ptr coloriter+2 ; restore color
  1112.                     ; speed not critical here in orbit land
  1113.  
  1114. calcmandfpasm_ret_87:
  1115.     UNFRAME <si,di>                 ; pop stack frame
  1116.     fwait                ; just to make sure
  1117.     ret
  1118.  
  1119. over_bailout_87:                        ; x^2 y^2 1 xy Cx Cy b
  1120. ; outside
  1121.     mov     dx,cx
  1122.     mov     ax,bx
  1123.     sub     ax,10                   ; 10 more next time before checking
  1124.     sbb     dx,0
  1125.     jns     no_fix_underflow_87
  1126. ; if the number of iterations was within 10 of maxit, then subtracting
  1127. ; 10 would underflow and cause periodicity checking to start right
  1128. ; away.  Catching a period doesn't occur as often in the pixels at
  1129. ; the edge of the set anyway.
  1130.     sub     ax,ax                   ; don't check next time
  1131.     mov     dx,ax
  1132. no_fix_underflow_87:
  1133.     mov     word ptr oldcoloriter,ax ; check when past this - 10 next time
  1134.     mov     word ptr oldcoloriter+2,dx ; check when past this - 10 next time
  1135.     mov     ax,word ptr maxit
  1136.     mov     dx,word ptr maxit+2
  1137.     sub     ax,bx                   ; leave 'times through loop' in ax
  1138.     sbb     dx,cx                   ; and dx
  1139.  
  1140. ; zero color fix
  1141.     jnz     zero_color_fix_87
  1142.     cmp     ax,0
  1143.     jnz     zero_color_fix_87
  1144.     inc     ax                      ; if (ax == 0 ) ax = 1
  1145. zero_color_fix_87:
  1146.     mov     word ptr realcoloriter,ax   ; save unadjusted realcolor
  1147.     mov     word ptr realcoloriter+2,dx ; save unadjusted realcolor
  1148.     sub     kbdcount,ax                 ; adjust the keyboard count
  1149.  
  1150.     cmp     outside,-1              ; iter ? (most common case)
  1151.     je      pop_stack_7_87
  1152.     cmp     outside,-2        ; outside <= -2 ?
  1153.     jle     special_outside_87      ; yes, go do special outside options
  1154.     mov     ax,outside              ; use outside color
  1155.     sub     dx,dx
  1156.     jmp     pop_stack_7_87
  1157. special_outside_87:
  1158.     call    near ptr special_outside
  1159.     jmp     pop_stack_7_87
  1160.  
  1161. calcmandfpasm  ENDP
  1162.  
  1163. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1164. ; Since periodicity checking is used most of the time, I decided to
  1165. ; separate the periodicity_check routines into a _287_387 version
  1166. ; and an _87 version to achieve a slight increase in speed.  The
  1167. ; epsilon_cross, show_orbit_xy, and special_outside routines are less
  1168. ; frequently used and therefore have been implemented as single routines
  1169. ; usable by the 8087 and up. -Wes
  1170. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1171. .286
  1172. .287
  1173. periodicity_check_287_387   PROC    NEAR
  1174. ; REMEMBER, the cx counter is counting BACKWARDS from maxit to 0
  1175.                     ; fpu stack is either
  1176.                     ; y x Cx Cy b (387)
  1177.                     ; y 1 x Cx Cy b (287/emul)
  1178.     cmp     fpu,387
  1179.     jb      pc_load_x
  1180.     fld     st(1)                   ; if 387
  1181.     jmp     short pc_end_load_x
  1182. pc_load_x:
  1183.     fld     st(2)                   ; if 287/emul
  1184. pc_end_load_x:
  1185.                     ; x y ...
  1186.     test    cx,word ptr savedand+2  ; save on 0, check on anything else
  1187.     jnz     do_check_287_387        ;  time to save a new "old" value
  1188.     test    bx,word ptr savedand    ; save on 0, check on anything else
  1189.     jnz     do_check_287_387        ;  time to save a new "old" value
  1190.  
  1191. ; save last value                       ; fpu stack is
  1192.     fstp    savedx                  ; x y ...
  1193.     fst     savedy                  ; y ...
  1194.     dec     savedincr               ; time to lengthen the periodicity?
  1195.     jnz     per_check_287_387_ret   ; if not 0, then skip
  1196.     shl     word ptr savedand,1     ; savedand = (savedand << 1) + 1
  1197.     rcl     word ptr savedand+2,1   ; savedand = (savedand << 1) + 1
  1198.     add     word ptr savedand,1     ; for longer periodicity
  1199.     adc     word ptr savedand+2,0   ; for longer periodicity
  1200.     mov     ax,nextsavedincr      ; and restart counter
  1201.     mov     savedincr,ax      ; and restart counter
  1202.     ret                             ; y ...
  1203.  
  1204. do_check_287_387:                       ; fpu stack is
  1205.                     ; x y ...
  1206.     fsub    savedx                  ; x-savedx y ...
  1207.     fabs                            ; |x-savedx| y ...
  1208.     fcomp   closenuff               ; y ...
  1209.     fstsw   ax
  1210.     sahf
  1211.     ja      per_check_287_387_ret
  1212.     fld     st                      ; y y ...
  1213.     fsub    savedy                  ; y-savedy y ...
  1214.     fabs                            ; |y-savedy| y ...
  1215.     fcomp   closenuff               ; y ...
  1216.     fstsw   ax
  1217.     sahf
  1218.     ja      per_check_287_387_ret
  1219.                     ; caught a cycle!!!
  1220.     mov     word ptr oldcoloriter,-1    ; check periodicity immediately next time
  1221.     mov     word ptr oldcoloriter+2,-1    ; check periodicity immediately next time
  1222.  
  1223.     mov     ax,word ptr maxit
  1224.     mov     dx,word ptr maxit+2
  1225.     mov     word ptr realcoloriter,ax ; save unadjusted realcolor as maxit
  1226.     mov     word ptr realcoloriter+2,dx ; save unadjusted realcolor as maxit
  1227.     sub     dx,cx                   ; subtract half c
  1228.     sbb     ax,bx                   ; subtract half c
  1229.     sub     kbdcount,ax             ; adjust the keyboard count
  1230.     mov     ax,periodicity_color    ; set color
  1231.     sub     dx,dx
  1232.     sub     cx,cx                   ; flag to exit cx loop immediately
  1233.     mov     bx,cx
  1234.  
  1235. per_check_287_387_ret:
  1236.     ret
  1237. periodicity_check_287_387   ENDP
  1238.  
  1239. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1240. .386
  1241. .387
  1242. periodicity_check_386_387   PROC    NEAR
  1243. ; REMEMBER, the cx counter is counting BACKWARDS from maxit to 0
  1244.                     ; fpu stack is
  1245.                     ; y x Cx Cy b
  1246.     fld     st(1)                   ;
  1247.                     ; x y ...
  1248.     test    ecx,savedand    ; save on 0, check on anything else
  1249.     jnz     do_check_386_387        ;  time to save a new "old" value
  1250.  
  1251. ; save last value                       ; fpu stack is
  1252.     fstp    savedx                  ; x y ...
  1253.     fst     savedy                  ; y ...
  1254.     dec     savedincr               ; time to lengthen the periodicity?
  1255.     jnz     per_check_386_387_ret   ; if not 0, then skip
  1256.     shl     savedand,1              ; savedand = (savedand << 1) + 1
  1257.     inc     savedand                ; for longer periodicity
  1258.     mov     ax,nextsavedincr       ; and restart counter
  1259.     mov     savedincr,ax       ; and restart counter
  1260.     ret                             ; y ...
  1261.  
  1262. do_check_386_387:                       ; fpu stack is
  1263.                     ; x y ...
  1264.     fsub    savedx                  ; x-savedx y ...
  1265.     fabs                            ; |x-savedx| y ...
  1266.     fcomp   closenuff               ; y ...
  1267.     fstsw   ax
  1268.     sahf
  1269.     ja      per_check_386_387_ret
  1270.     fld     st                      ; y y ...
  1271.     fsub    savedy                  ; y-savedy y ...
  1272.     fabs                            ; |y-savedy| y ...
  1273.     fcomp   closenuff               ; y ...
  1274.     fstsw   ax
  1275.     sahf
  1276.     ja      per_check_386_387_ret
  1277.                     ; caught a cycle!!!
  1278.     mov     oldcoloriter,-1        ; check periodicity immediately next time
  1279.  
  1280.     mov     eax,maxit
  1281.     mov     realcoloriter,eax      ; save unadjusted realcolor as maxit
  1282.     sub     eax,ecx                ; subtract half c
  1283.     sub     kbdcount,ax            ; adjust the keyboard count
  1284.     sub     eax,eax                ; clear top half of eax for next
  1285.     mov     ax,periodicity_color   ; set color
  1286.     sub     ecx,ecx                ; flag to exit cx loop immediately
  1287.  
  1288. per_check_386_387_ret:
  1289.     ret
  1290. periodicity_check_386_387   ENDP
  1291.  
  1292. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1293. .8086
  1294. .8087
  1295. periodicity_check_87    PROC    NEAR
  1296. ; just like periodicity_check_287_387 except for the use of
  1297. ;       fstsw tmp_word
  1298. ; instead of
  1299. ;       fstsw ax
  1300.  
  1301. ; REMEMBER, the cx counter is counting BACKWARDS from maxit to 0
  1302.     fld     st(2)                   ; x y ...
  1303.     test    cx,word ptr savedand+2  ; save on 0, check on anything else
  1304.     jnz     do_check_87             ;  time to save a new "old" value
  1305.     test    bx,word ptr savedand    ; save on 0, check on anything else
  1306.     jnz     do_check_87             ;  time to save a new "old" value
  1307.  
  1308. ; save last value                       ; fpu stack is
  1309.                     ; x y ...
  1310.     fstp    savedx                  ; y ...
  1311.     fst     savedy                  ; y ...
  1312.     dec     savedincr               ; time to lengthen the periodicity?
  1313.     jnz     per_check_87_ret        ; if not 0, then skip
  1314.     shl     word ptr savedand,1     ; savedand = (savedand << 1) + 1
  1315.     rcl     word ptr savedand+2,1   ; savedand = (savedand << 1) + 1
  1316.     add     word ptr savedand,1     ; for longer periodicity
  1317.     adc     word ptr savedand+2,0   ; for longer periodicity
  1318.     mov     ax,nextsavedincr        ; and restart counter
  1319.     mov     savedincr,ax             ; and restart counter
  1320.     ret                             ; y ...
  1321.  
  1322. do_check_87:                            ; fpu stack is
  1323.                     ; x y ...
  1324.     fsub    savedx                  ; x-savedx y ...
  1325.     fabs                            ; |x-savedx| y ...
  1326.     fcomp   closenuff               ; y ...
  1327.     fstsw   tmp_word
  1328.     fwait
  1329.     mov     ax,tmp_word
  1330.     sahf
  1331.     ja      per_check_87_ret
  1332.     fld     st                      ; y y ...
  1333.     fsub    savedy                  ; y-savedy y ...
  1334.     fabs                            ; |y-savedy| y ...
  1335.     fcomp   closenuff               ; y ...
  1336.     fstsw   tmp_word
  1337.     fwait
  1338.     mov     ax,tmp_word
  1339.     sahf
  1340.     ja      per_check_87_ret
  1341.                     ; caught a cycle!!!
  1342.     mov     word ptr oldcoloriter,-1    ; check periodicity immediately next time
  1343.     mov     word ptr oldcoloriter+2,-1    ; check periodicity immediately next time
  1344.  
  1345.     mov     ax,word ptr maxit
  1346.     mov     dx,word ptr maxit+2
  1347.     mov     word ptr realcoloriter,ax ; save unadjusted realcolor as maxit
  1348.     mov     word ptr realcoloriter+2,dx ; save unadjusted realcolor as maxit
  1349.     sub     dx,cx                   ; subtract half c
  1350.     sbb     ax,bx                   ; subtract half c
  1351.     sub     kbdcount,ax             ; adjust the keyboard count
  1352.     mov     ax,periodicity_color    ; set color
  1353.     sub     dx,dx
  1354.     sub     cx,cx                   ; flag to exit cx loop immediately
  1355.     mov     bx,cx
  1356.  
  1357. per_check_87_ret:
  1358.     ret
  1359. periodicity_check_87       ENDP
  1360.  
  1361. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1362. .8086
  1363. .8087
  1364. epsilon_cross   PROC    NEAR
  1365.                     ; fpu stack is either
  1366.                     ; y x Cx Cy b (387)
  1367.                     ; y 1 x Cx Cy b (287/87/emul)
  1368.     cmp     fpu,387
  1369.     jb      ec_load_x
  1370.     fld     st(1)                   ; if 387
  1371.     jmp     short ec_end_load_x
  1372. ec_load_x:
  1373.     fld     st(2)                   ; if 287/87/emul
  1374. ec_end_load_x:                          ; x y ...
  1375.  
  1376.     fabs                            ; |x| y 1 x Cx Cy b
  1377.     fcomp   close                   ; y 1 x Cx Cy b
  1378.     fstsw   tmp_word
  1379.     fwait
  1380.     mov     ax,tmp_word
  1381.     sahf
  1382.     jae     no_x_epsilon_cross
  1383.     mov     ax,word ptr maxit       ; x is close to y axis
  1384.     mov     dx,word ptr maxit+2     ; x is close to y axis
  1385.     sub     ax,bx                   ; leave 'times through loop' in ax,dx
  1386.     sbb     dx,cx                   ; leave 'times through loop' in ax,dx
  1387. ; zero color fix
  1388.     jnz     zero_color_fix_1
  1389.     cmp     ax,0
  1390.     jnz     zero_color_fix_1
  1391.     inc     ax                      ; if (ax == 0 ) ax = 1
  1392. zero_color_fix_1:
  1393.     mov     word ptr realcoloriter,ax   ; save unadjusted realcolor
  1394.     mov     word ptr realcoloriter+2,dx ; save unadjusted realcolor
  1395.     sub     kbdcount,ax                 ; adjust the keyboard count
  1396.     mov     ax,GREEN                ;
  1397.     sub     dx,dx
  1398.     sub     cx,cx                   ; flag to end loop
  1399.     mov     bx,cx
  1400.     mov     word ptr oldcoloriter,bx    ; don't check next time
  1401.     mov     word ptr oldcoloriter+2,cx  ; don't check next time
  1402.     ret                             ; return
  1403. no_x_epsilon_cross:                     ; y 1 x Cx Cy b
  1404.     fld     st                      ; y y 1 x Cx Cy b
  1405.     fabs                            ; |y| y 1 x Cx Cy b
  1406.     fcomp   close                   ; y 1 x Cx Cy b
  1407.     fstsw   tmp_word
  1408.     fwait
  1409.     mov     ax,tmp_word
  1410.     sahf
  1411.     jae     no_y_epsilon_cross
  1412.     mov     ax,word ptr maxit       ; y is close to x axis
  1413.     mov     dx,word ptr maxit+2     ; y is close to x axis
  1414.     sub     ax,bx                   ; leave 'times through loop' in ax,dx
  1415.     sbb     dx,cx                   ; leave 'times through loop' in ax,dx
  1416. ; zero color fix
  1417.     jnz     zero_color_fix_2
  1418.     cmp     ax,0
  1419.     jnz     zero_color_fix_2
  1420.     inc     ax                      ; if (ax == 0 ) ax = 1
  1421. zero_color_fix_2:
  1422.     mov     word ptr realcoloriter,ax  ; save unadjusted realcolor
  1423.     mov     word ptr realcoloriter+2,dx  ; save unadjusted realcolor
  1424.     sub     kbdcount,ax                  ; adjust the keyboard count
  1425.     mov     ax,YELLOW
  1426.     sub     dx,dx
  1427.     sub     cx,cx                   ; flag to end loop
  1428.     mov     bx,cx
  1429.     mov     word ptr oldcoloriter,bx   ; don't check next time
  1430.     mov     word ptr oldcoloriter+2,cx ; don't check next time
  1431.     ret                             ; return
  1432. no_y_epsilon_cross:
  1433.     ret
  1434. epsilon_cross   ENDP
  1435. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1436. .386
  1437. .387
  1438. epsilon_cross_386_387   PROC    NEAR
  1439.                     ; fpu stack is
  1440.                     ; y x Cx Cy b
  1441.     fld     st(1)                   ;
  1442.     fabs                            ; |x| y x Cx Cy b
  1443.     fcomp   close                   ; y x Cx Cy b
  1444.     fstsw   tmp_word
  1445.     fwait
  1446.     mov     ax,tmp_word
  1447.     sahf
  1448.     jae     no_x_epsilon_cross
  1449.     mov     eax,maxit               ; x is close to y axis
  1450.     sub     eax,ecx                 ; leave 'times through loop' in eax
  1451. ; zero color fix
  1452.     jnz     zero_color_fix_1
  1453.     inc     eax                     ; if (eax == 0 ) eax = 1
  1454. zero_color_fix_1:
  1455.     mov     realcoloriter,eax       ; save unadjusted realcolor
  1456.     sub     kbdcount,ax             ; adjust the keyboard count
  1457.     mov     eax,GREEN               ;
  1458.     sub     ecx,ecx                 ; flag to end loop
  1459.     mov     oldcoloriter,ecx        ; don't check next time
  1460.     ret                             ; return
  1461. no_x_epsilon_cross:                     ; y 1 x Cx Cy b
  1462.     fld     st                      ; y y 1 x Cx Cy b
  1463.     fabs                            ; |y| y 1 x Cx Cy b
  1464.     fcomp   close                   ; y 1 x Cx Cy b
  1465.     fstsw   tmp_word
  1466.     fwait
  1467.     mov     ax,tmp_word
  1468.     sahf
  1469.     jae     no_y_epsilon_cross
  1470.     mov     eax,maxit               ; y is close to x axis
  1471.     sub     eax,ecx                 ; leave 'times through loop' in ax,dx
  1472. ; zero color fix
  1473.     jnz     zero_color_fix_2
  1474.     inc     eax                     ; if (eax == 0 ) eax = 1
  1475. zero_color_fix_2:
  1476.     mov     realcoloriter,eax       ; save unadjusted realcolor
  1477.     sub     kbdcount,ax             ; adjust the keyboard count
  1478.     mov     eax,YELLOW
  1479.     sub     ecx,ecx                 ; flag to end loop
  1480.     mov     oldcoloriter,ecx        ; don't check next time
  1481.     ret                             ; return
  1482. no_y_epsilon_cross:
  1483.     ret
  1484. epsilon_cross_386_387   ENDP
  1485. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1486. .8086
  1487. .8087
  1488. show_orbit_xy   PROC NEAR USES cx si di
  1489.     local    tmp_ten_byte_0:tbyte    ; stupid klooge for MASM 5.1 LOCAL bug
  1490.     local    tmp_ten_byte_1:tbyte
  1491.     local    tmp_ten_byte_2:tbyte
  1492.     local    tmp_ten_byte_3:tbyte
  1493.     local    tmp_ten_byte_4:tbyte
  1494.     local    tmp_ten_byte_5:tbyte
  1495.     local    tmp_ten_byte_6:tbyte
  1496. ; USES is needed because in all likelyhood, plot_orbit surely
  1497. ; uses these registers.  It's ok to have to push/pop's here in the
  1498. ; orbits as speed is not crucial when showing orbits.
  1499.  
  1500.                     ; fpu stack is either
  1501.                     ; y x Cx Cy b (387)
  1502.                     ; y 1 x Cx Cy b (287/87/emul)
  1503.     cmp     fpu,387
  1504.     jb      so_load_x
  1505.     fld     st(1)                   ; if 387
  1506.     jmp     short so_end_load_x
  1507. so_load_x:
  1508.     fld     st(2)                   ; if 287/87/emul
  1509. so_end_load_x:
  1510.                     ; x y ...
  1511.                     ; and needs to returned as
  1512.                     ; y ...
  1513.  
  1514.     fstp    orbit_real              ; y ...
  1515.     fst     orbit_imag              ; y ...
  1516.     mov     ax,-1                   ; color for plot orbit
  1517.     push    ax                      ;       ...
  1518. ; since the number fpu registers that plot_orbit() preserves is compiler
  1519. ; dependant, it's best to fstp the entire stack into 10 byte memories
  1520. ; and fld them back after plot_orbit() returns.
  1521.     fstp    tmp_ten_byte_1          ; store the stack in 80 bit form
  1522.     fstp    tmp_ten_byte_2
  1523.     fstp    tmp_ten_byte_3
  1524.     fstp    tmp_ten_byte_4
  1525.     fstp    tmp_ten_byte_5
  1526.     cmp     fpu,287                 ; with 287/87/emul the stack is 6 high
  1527.     jg      no_store_6              ; with 387 it is only 5 high
  1528.     fstp    tmp_ten_byte_6
  1529. no_store_6:
  1530.     fwait                           ; just to be safe
  1531.     push    word ptr orbit_imag+6   ; co-ordinates for plot orbit
  1532.     push    word ptr orbit_imag+4   ;       ...
  1533.     push    word ptr orbit_imag+2   ;       ...
  1534.     push    word ptr orbit_imag     ;       ...
  1535.     push    word ptr orbit_real+6   ; co-ordinates for plot orbit
  1536.     push    word ptr orbit_real+4   ;       ...
  1537.     push    word ptr orbit_real+2   ;       ...
  1538.     push    word ptr orbit_real     ;       ...
  1539.     call    far ptr plot_orbit      ; display the orbit
  1540.     add     sp,9*2                  ; clear out the parameters
  1541.  
  1542.         cmp     fpu,287
  1543.         jg      no_load_6
  1544.         fld     tmp_ten_byte_6          ; load them back in reverse order
  1545. no_load_6:
  1546.     fld    tmp_ten_byte_5
  1547.     fld    tmp_ten_byte_4
  1548.     fld    tmp_ten_byte_3
  1549.     fld    tmp_ten_byte_2
  1550.     fld    tmp_ten_byte_1
  1551.     fwait                           ; just to be safe
  1552.     ret
  1553. show_orbit_xy   ENDP
  1554. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1555. .8086
  1556. .8087
  1557. special_outside PROC NEAR
  1558. ; When type casting floating point variables to integers in C, the decimal
  1559. ; is truncated.  When using FIST in asm, the value is rounded.  Using
  1560. ; "FSUB round_down_half" causes the values to be rounded down.
  1561.  
  1562.     cmp     outside,-2
  1563.     jne     not_real
  1564.     fld     newx
  1565.     fsub    round_down_half
  1566.     fistp   tmp_dword
  1567.     add     ax,7
  1568.     adc     dx,0
  1569.     fwait
  1570.     add     ax,word ptr tmp_dword
  1571.     adc     dx,word ptr tmp_dword+2
  1572.     jmp     check_color
  1573. not_real:
  1574.     cmp     outside,-3
  1575.     jne     not_imag
  1576.     fld     newy
  1577.     fsub    round_down_half
  1578.     fistp   tmp_dword
  1579.     add     ax,7
  1580.     adc     dx,0
  1581.     fwait
  1582.     add     ax,word ptr tmp_dword
  1583.     adc     dx,word ptr tmp_dword+2
  1584.     jmp     check_color
  1585. not_imag:
  1586.     cmp     outside,-4
  1587.     jne     not_mult
  1588.     fld     newy
  1589.     ftst                    ; check to see if newy == 0
  1590.     fstsw   tmp_word
  1591.     push    ax              ; save current ax value
  1592.     fwait
  1593.     mov     ax,tmp_word
  1594.     sahf
  1595.     pop     ax              ; retrieve ax (does not affect flags)
  1596.     jne     non_zero_y
  1597.     ret                     ; if y==0, return with normal ax
  1598. non_zero_y:
  1599.     fdivr   newx            ; newx/newy
  1600.     mov     word ptr tmp_dword,ax
  1601.     mov     word ptr tmp_dword+2,dx
  1602.     fimul   tmp_dword       ; (ax,dx)*newx/newy  (Use FIMUL instead of MUL
  1603.     fsub    round_down_half ; to make it match the C code.)
  1604.     fistp   tmp_dword
  1605.     fwait
  1606.     mov     ax,word ptr tmp_dword
  1607.     mov     dx,word ptr tmp_dword+2
  1608.     jmp     short check_color
  1609. not_mult:
  1610.     cmp     outside,-5
  1611.     jne     not_sum
  1612.     fld     newx
  1613.     fadd    newy            ; newx+newy
  1614.     fsub    round_down_half
  1615.     fistp   tmp_dword
  1616.     fwait
  1617.     add     ax,word ptr tmp_dword
  1618.     adc     dx,word ptr tmp_dword+2
  1619. not_sum:
  1620.     cmp     outside,-6      ; currently always equal, but put here
  1621.     jne     not_atan        ; for future outside types
  1622.     call    near ptr FPUatan ; return with atan on FPU stack
  1623.     fmul    one_8_zero      ; 180*Angle
  1624.     fldpi                   ; pi 180*Angle
  1625.     fdiv                    ; 180*Angle/pi
  1626.     fabs
  1627.     fsub    round_down_half
  1628.     fistp   tmp_dword
  1629.     fwait
  1630.     mov     ax,word ptr tmp_dword
  1631.     mov     dx,word ptr tmp_dword+2
  1632.  
  1633. not_atan:
  1634. check_color:
  1635.     cmp     dx,word ptr maxit+2     ; use UNSIGNED comparison
  1636.     jb      special_outside_ret     ; color < 0 || color > maxit
  1637.     cmp     ax,word ptr maxit       ; use UNSIGNED comparison
  1638.     jbe     special_outside_ret     ; color < 0 || color > maxit
  1639.     sub     ax,ax                   ; ax = 0
  1640.     mov     dx,ax                   ; dx = 0
  1641. special_outside_ret:
  1642.     ret
  1643. special_outside ENDP
  1644. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1645. .386
  1646. .387
  1647. special_outside_386_387 PROC NEAR
  1648. ; When type casting floating point variables to integers in C, the decimal
  1649. ; is truncated.  When using FIST in asm, the value is rounded.  Using
  1650. ; "FSUB round_down_half" causes the values to be rounded down.
  1651.  
  1652.     cmp     outside,-2
  1653.     jne     not_real
  1654.     fld     newx
  1655.     fsub    round_down_half
  1656.     fistp   tmp_dword
  1657.     add     eax,7
  1658.     fwait
  1659.     add     eax,tmp_dword
  1660.     jmp     check_color
  1661. not_real:
  1662.     cmp     outside,-3
  1663.     jne     not_imag
  1664.     fld     newy
  1665.     fsub    round_down_half
  1666.     fistp   tmp_dword
  1667.     add     eax,7
  1668.     fwait
  1669.     add     eax,tmp_dword
  1670.     jmp     check_color
  1671. not_imag:
  1672.     cmp     outside,-4
  1673.     jne     not_mult
  1674.     fld     newy
  1675.     ftst                    ; check to see if newy == 0
  1676.     fstsw   tmp_word
  1677.     push    ax              ; save current ax value
  1678.     fwait
  1679.     mov     ax,tmp_word
  1680.     sahf
  1681.     pop     ax              ; retrieve ax (does not affect flags)
  1682.     jne     non_zero_y
  1683.     ret                     ; if y==0, return with normal ax
  1684. non_zero_y:
  1685.     fdivr   newx            ; newx/newy
  1686.     mov     tmp_dword,eax
  1687.     fimul   tmp_dword       ; (ax,dx)*newx/newy  (Use FIMUL instead of MUL
  1688.     fsub    round_down_half ; to make it match the C code.)
  1689.     fistp   tmp_dword
  1690.     fwait
  1691.     mov     eax,tmp_dword
  1692.     jmp     short check_color
  1693. not_mult:
  1694.     cmp     outside,-5
  1695.     jne     not_sum
  1696.     fld     newx
  1697.     fadd    newy            ; newx+newy
  1698.     fsub    round_down_half
  1699.     fistp   tmp_dword
  1700.     fwait
  1701.     add     eax,tmp_dword
  1702. not_sum:
  1703.     cmp     outside,-6      ; currently always equal, but put here
  1704.     jne     not_atan        ; for future outside types
  1705.     fld     newy            ; newy
  1706.     fld     newx            ; newx newy
  1707.     fpatan                  ; arctan(y/x)
  1708.     fmul    one_8_zero      ; 180*atan
  1709.     fldpi                   ; pi 180*atan
  1710.     fdiv                    ; 180*atan/pi
  1711.     fabs
  1712.     fsub    round_down_half
  1713.     fistp   tmp_dword
  1714.     fwait
  1715.     mov     eax,tmp_dword
  1716.  
  1717. not_atan:
  1718. check_color:
  1719.     cmp     eax,maxit               ; use UNSIGNED comparison
  1720.     jbe     special_outside_ret     ; color < 0 || color > maxit
  1721.     sub     eax,eax                 ; eax = 0
  1722. special_outside_ret:
  1723.     ret
  1724. special_outside_386_387 ENDP
  1725.  
  1726. .8086   ;just to be sure
  1727. .8087
  1728.  
  1729. FPUatan PROC NEAR
  1730. ; This is derived from FPUcplxlog in fpu087.asm
  1731. ; The arctan is returned on the FPU stack
  1732. LOCAL Status:word
  1733.  
  1734.     mov     ax, word ptr newy+6
  1735.     or      ax, word ptr newx+6
  1736.     jnz     NotBothZero
  1737.  
  1738.     fldz
  1739.     jmp     atandone
  1740.  
  1741. NotBothZero:
  1742.     fld     newy            ; newy
  1743.     fld     newx            ; newx newy
  1744.  
  1745.     mov     dh, BYTE PTR newx+7
  1746.     or      dh, dh
  1747.     jns     ChkYSign
  1748.  
  1749.     fchs                    ; |newx| newy
  1750.  
  1751. ChkYSign:
  1752.     mov     dl, BYTE PTR newy+7
  1753.     or      dl, dl
  1754.     jns     ChkMagnitudes
  1755.  
  1756.     fxch                    ; newy |newx|
  1757.     fchs                    ; |newy| |newx|
  1758.     fxch                    ; |newx| |newy|
  1759.  
  1760. ChkMagnitudes:
  1761.     fcom    st(1)           ; |newx| |newy|
  1762.     fstsw   Status
  1763.     test    Status, 4500h
  1764.     jz      XisGTY
  1765.  
  1766.     test    Status, 4000h
  1767.     jz      XneY
  1768.  
  1769. ; newx = newy and atan = pi/4
  1770.     fstp    st              ; newy
  1771.     fstp    st              ; empty
  1772.     fldpi                   ; pi
  1773.     fdiv    _4_             ; pi/4
  1774.     jmp     short ChkSignZ
  1775.  
  1776. XneY:
  1777.     fxch                    ; newy newx
  1778.     fpatan                  ; pi/2 - Angle
  1779.     fldpi                   ; pi, pi/2 - Angle
  1780.     fdiv    _2_             ; pi/2, pi/2 - Angle
  1781.     fsubr                   ; Angle
  1782.     jmp     short ChkSignZ
  1783.  
  1784. XisGTY:
  1785.     fpatan                  ; pi-Angle or Angle+pi
  1786.  
  1787. ChkSignZ:
  1788.     or      dh, dh
  1789.     js      NegX
  1790.  
  1791.     or      dl, dl
  1792.     jns     short atandone
  1793.  
  1794.     fchs
  1795.     jmp     short atandone
  1796.  
  1797. NegX:
  1798.     or      dl, dl
  1799.     js      QuadIII
  1800.  
  1801.     fldpi                   ; pi, pi-Angle
  1802.     fsubr                   ; Angle
  1803.     jmp     short atandone
  1804.  
  1805. QuadIII:
  1806.     fldpi                   ; pi, Angle+pi
  1807.     fsub                    ; Angle
  1808.  
  1809. atandone:
  1810.     ret                     ; Leave result on FPU stack and return
  1811.  
  1812. FPUatan ENDP
  1813.  
  1814. END
  1815.